package com.minelx.datamicroscope.core.query;

import com.alibaba.fastjson.JSONObject;
import com.minelx.datamicroscope.core.condition.RawCondition;
import com.minelx.datamicroscope.core.index.Index;
import com.minelx.datamicroscope.core.index.IndexFactory;
import com.minelx.datamicroscope.core.query.literalcondition.LiteralCondition;
import com.minelx.datamicroscope.core.values.CommonTable;
import io.gitee.minelx.filesystem.File;
import io.gitee.minelx.filesystem.TempPath;
import io.gitee.minelx.filesystem.init.OpenPolicy;

import java.util.List;
import java.util.stream.Stream;

import static com.minelx.datamicroscope.core.query.QueryPathFactory.convertToAliasedKeys;
import static java.util.Collections.emptyList;
import static java.util.stream.Collectors.toList;

public class FirstCollectionQuery {
    private final String resourceName;

    private final List<AliasedKey> collectingKeys;

    private final List<LiteralCondition> literalConditions;

    private FirstCollectionQuery(String resourceName,
                                 List<AliasedKey> collectingKeys,
                                 List<LiteralCondition> literalConditions) {
        this.resourceName = resourceName;
        this.collectingKeys = collectingKeys;
        this.literalConditions = literalConditions;
    }

    ResourceMapping rootResourceMapping(String rootResourceURI) {
        query(rootResourceURI);
        Resource rootResource = Resource.root(
                TempPath.tempFileDirectoryAtWorkingDir(),
                Query.localPandas(),
                rootResourceURI,
                containedKeys());
        return new ResourceMapping(resourceName, rootResource);
    }

    public void query(String destinationURI) {
        File destination = Query.onlyLocalFSRegistry().file(destinationURI, OpenPolicy.CREATE);
        try (TempPath temp = TempPath.random()) {
            List<RawCondition> rawConditions = parseRawConditions(temp);
            Index index = IndexFactory.onlineIndexAndLocalStoredPandasFile()
                    .createIndex(emptyList(),
                            rawConditions,
                            CollectingResource.create(collectingKeys),
                            destination);
            index.list();
        }
    }

    public List<AliasedKey> containedKeys() {
        return collectingKeys;
    }

    private List<RawCondition> parseRawConditions(TempPath directory) {
        return literalConditions.stream()
                .map(literalCondition -> literalCondition.toRawCondition(directory))
                .collect(toList());
    }

    public static FirstCollectionQuery from(JSONObject data) {
        RawConditionFactory rawConditionFactory = new RawConditionFactory(Query.onlyLocalFSRegistry());
        CommonTable joinedTable = CommonTable.from(data.getString("join"));
        List<AliasedKey> collectingKeys = convertToAliasedKeys(joinedTable, data.getJSONObject("collecting"));
        String resourceName = data.getString("resourceName");
        List<LiteralCondition> literalConditions = Stream.concat(
                        data.getJSONArray("preset_conditions")
                                .toJavaList(JSONObject.class).stream()
                                .map(LiteralCondition::fromContentAndField)
                                .collect(toList()).stream(),
                        QueryPathFactory.extractConditions(data, joinedTable).stream()
                                .map(keyOperandCondition -> LiteralCondition.keyOperand(rawConditionFactory, keyOperandCondition))
                                .collect(toList()).stream())
                .collect(toList());
        return new FirstCollectionQuery(resourceName, collectingKeys, literalConditions);
    }
}
